package com.cg.controller;

import com.cg.context.BaseContext;
import com.cg.common.Result;
import com.cg.dto.ChatSessionDTO;
import com.cg.dto.ChatMessageDTO;
import com.cg.service.AiChatService;
import com.cg.service.ChatMemoryService;
import com.cg.service.ResumeAnalysisService;
import com.cg.service.UserService;
import com.cg.service.InterviewSessionService;
import com.cg.mapper.InterviewMapper;
import com.cg.utils.JwtUtil;
import dev.langchain4j.model.chat.ChatModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.nio.charset.StandardCharsets;
import com.cg.dto.InterviewSessionDTO;
import com.cg.dto.InterviewEvaluationDTO;
import com.cg.dto.InterviewMessageDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.response.ChatResponse;

/**
 * AI对话控制器
 */
@RestController
@RequestMapping("/ai")
@Slf4j
public class AiController {

    @Autowired
    private ChatModel myQwenChatModel;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private AiChatService aiChatService;
    
    @Autowired
    private ChatMemoryService chatMemoryService;
    
    @Autowired
    private InterviewSessionService interviewSessionService;

    @Autowired
    private UserService userService;

    @Autowired
    private ResumeAnalysisService resumeAnalysisService;

    @Autowired
    private InterviewMapper interviewMapper;


    /**
     * 系统提示词
     */
    private static final String SYSTEM_MESSAGE = """
            你是一个专业的编程学习和求职面试助手，专门帮助用户提升编程技能和准备技术面试。
            
            你的主要职责包括：
            1. 解答编程技术问题，提供清晰的代码示例和解释
            2. 协助用户准备技术面试，包括算法、数据结构、系统设计等
            3. 提供编程学习建议和职业规划指导
            4. 分析简历和项目，给出改进建议
            
            请始终保持专业、友好的态度，提供准确、实用的建议。
            """;

    /**
     * AI对话接口 - 支持流式响应（带记忆功能）
     * @param message 用户消息
     * @param token JWT Token (通过URL参数传递，因为SSE不支持自定义请求头)
     * @param sessionId 当前会话ID (可选，如果提供则使用该会话，否则后端根据用户ID获取或创建)
     * @return 流式响应
     */
    @GetMapping(value = "/chat", produces = "text/event-stream")
    public Flux<ServerSentEvent<String>> aiTalk(
            @RequestParam("message") String message,
            @RequestParam("token") String token,
            @RequestParam(value = "sessionId", required = false) Long sessionId) { // 添加sessionId参数

        // 验证Token并获取用户ID
        Long userId;
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            userId = Long.valueOf(claims.get("userId").toString());
            BaseContext.setCurrentId(userId);
        } catch (Exception e) {
            log.error("Token验证失败: {}", e.getMessage());
            return Flux.error(new RuntimeException("认证失败"));
        }

        if (userId == null) {
            return Flux.error(new RuntimeException("用户未登录"));
        }

        // 如果没有提供sessionId，则获取或创建当前活跃会话
        Long currentSessionId = sessionId;
        if (currentSessionId == null) {
            try {
                ChatSessionDTO session = chatMemoryService.getOrCreateCurrentSession(userId);
                currentSessionId = session.getSessionId();
                log.info("未提供sessionId，自动获取或创建会话: sessionId={}, userId={}", currentSessionId, userId);
            } catch (Exception e) {
                log.error("获取或创建会话失败: userId={}, error={}", userId, e.getMessage());
                return Flux.error(new RuntimeException("获取或创建会话失败"));
            }
        }

        final Long finalSessionId = currentSessionId;
        final Long finalUserId = userId;

        log.info("用户 {} 发起AI对话: sessionId={}, message={}", userId, finalSessionId, message);

        // 改为真正的流式输出：直接将后端生成的 token 通过 SSE 推送
        return aiChatService.chatStream(finalUserId, finalSessionId, message)
                .map(chunk -> ServerSentEvent.<String>builder().data(chunk).build())
                .concatWith(Flux.just(ServerSentEvent.<String>builder().data("[DONE]").build()));
    }


    /**
     * 模拟面试流式接口：前端仅负责界面；后台拼装并使用 resources/interview-prompt.txt
     */
    @GetMapping(value = "/interview", produces = "text/event-stream")
    public Flux<ServerSentEvent<String>> interview(
            @RequestParam("token") String token,
            @RequestParam(value = "sessionId", required = false) Long sessionId,
            @RequestParam(value = "interviewSessionId", required = false) Long interviewSessionId,
            @RequestParam(value = "interviewerType", required = false) String interviewerType,
            @RequestParam(value = "topics", required = false) String topics,
            @RequestParam(value = "classicCount", required = false) Integer classicCount,
            @RequestParam(value = "projectCount", required = false) Integer projectCount,
            @RequestParam(value = "position", required = false) String position,
            @RequestParam(value = "resumePoints", required = false) String resumePoints,
            @RequestParam(value = "targetCompany", required = false) String targetCompany,
            @RequestParam(value = "message", required = false) String message
    ) {
        Long userId;
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            userId = Long.valueOf(claims.get("userId").toString());
            BaseContext.setCurrentId(userId);
        } catch (Exception e) {
            log.error("Token验证失败: {}", e.getMessage());
            return Flux.error(new RuntimeException("认证失败"));
        }
        if (userId == null) return Flux.error(new RuntimeException("用户未登录"));

        // 使用面试会话ID，如果没有则创建新的面试会话
        Long currentInterviewSessionId = interviewSessionId;
        if (currentInterviewSessionId == null) {
            try {
                // 创建新的面试会话，使用英文标题
                String interviewerTypeEn = getInterviewerTypeEn(interviewerType);
                String sessionTitle = "Interview-" + interviewerTypeEn + "-" + System.currentTimeMillis();
                InterviewSessionDTO session = interviewSessionService.createSession(
                    userId, null, sessionTitle, interviewerType, topics, classicCount, projectCount);
                currentInterviewSessionId = session.getId();
            } catch (Exception e) {
                log.error("创建面试会话失败: userId={}, error={}", userId, e.getMessage());
                return Flux.error(new RuntimeException("创建面试会话失败"));
            }
        } else {
            // 如果使用已存在的面试会话，从数据库读取已保存的配置
            try {
                InterviewSessionDTO existingSession = interviewSessionService.getSessionById(currentInterviewSessionId);
                if (existingSession != null) {
                    // 使用数据库中已保存的值，覆盖前端传递的参数
                    classicCount = existingSession.getClassicCount();
                    projectCount = existingSession.getProjectCount();
                    interviewerType = existingSession.getInterviewerType();
                    topics = existingSession.getTopics();
                    
                    log.info("使用已存在的面试会话配置: sessionId={}, classicCount={}, projectCount={}, interviewerType={}, topics={}", 
                            currentInterviewSessionId, classicCount, projectCount, interviewerType, topics);
                } else {
                    log.warn("面试会话不存在: sessionId={}", currentInterviewSessionId);
                    return Flux.error(new RuntimeException("面试会话不存在"));
                }
            } catch (Exception e) {
                log.error("获取面试会话配置失败: sessionId={}, error={}", currentInterviewSessionId, e.getMessage());
                return Flux.error(new RuntimeException("获取面试会话配置失败"));
            }
        }

        // 根据类型选择 resources/prompts 下的提示词文件
        String fileName = switch (interviewerType) {
            case "pressure", "1" -> "prompts/interview-pressure.txt";
            case "gentle", "2" -> "prompts/interview-gentle.txt";
            case "kpi", "3" -> "prompts/interview-kpi.txt";
            case "normal", "4" -> "prompts/interview-normal.txt";
            default -> "prompts/interview-normal.txt";
        };
        String promptTemplate;
        try {
            promptTemplate = new String(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream(fileName)).readAllBytes());
        } catch (Exception e) {
            log.error("读取面试提示词失败: {}", e.getMessage());
            return Flux.error(new RuntimeException("提示词文件缺失"));
        }

        // 若未显式提供 position 和 简历点，则从用户画像与最近一次解析中推断
        try {
            var user = userService.getUserById(userId);
            if (user != null) {
                if (position == null || position.isBlank()) {
                    position = user.getTargetPosition();
                }
                // 如果用户理想岗位包含Java且未提供topics，则给出Java相关默认主题
                if ((topics == null || topics.isBlank()) && user.getTargetPosition() != null && user.getTargetPosition().toLowerCase().contains("java")) {
                    topics = "Java、MySQL、Redis、消息队列、Spring、JUC、JVM、操作系统、计算机网络";
                }
            }
            
            // 获取简历解析结果，分别提取项目经历和其他信息
            if (resumePoints == null || resumePoints.isBlank()) {
                var latest = resumeAnalysisService.getLatestAnalysisByUser(userId);
                if (latest != null && latest.get("parseResult") != null) {
                    Object parseResult = latest.get("parseResult");
                    if (parseResult instanceof Map) {
                        Map<?, ?> parseMap = (Map<?, ?>) parseResult;
                        
                        // 专门提取项目经历用于项目挖掘题
                        Object projects = parseMap.get("projects");
                        if (projects != null) {
                            String projectInfo = limitText(String.valueOf(projects), 1000);
                            // 将项目信息单独存储，用于项目挖掘题
                            latest.put("projectInfo", projectInfo);
                        }
                        
                        // 将整体解析结果作为简历要点（用于技术题背景）
                        resumePoints = limitText(String.valueOf(parseResult), 1500);
                    } else {
                        resumePoints = limitText(String.valueOf(parseResult), 1500);
                    }
                }
            }
        } catch (Exception e) {
            log.warn("面试上下文获取失败(可忽略): {}", e.getMessage());
        }

        // 面试RAG：区分经典技术题和项目挖掘题 ==========
        boolean targetIsJava = position != null && position.toLowerCase().contains("java");
        if (targetIsJava) {
            try {
                String kb = loadResourceText("docs/程序员常见面试题.md");
                String filtered = filterKnowledgeByTopics(kb, topics);
                if (filtered != null && !filtered.isBlank()) {
                    // 经典技术题：从知识库中随机抽取
                    promptTemplate = promptTemplate + "\n\n# 经典技术题知识点（知识库参考，请随机抽取）\n" + 
                                   "**重要提醒：请从以下知识点中随机抽取 {{CLASSIC_COUNT}} 道经典技术题，不要按顺序或固定模式提问。每次面试应该有不同的题目组合。**\n\n" + 
                                   filtered + "\n";
                }
            } catch (Exception e) {
                log.warn("加载面试知识库失败(可忽略): {}", e.getMessage());
            }
        } else {
            // 非 Java 岗位：不注入知识库，忽略 topics，由模型根据职位与简历自由生成
            topics = "";
        }
        
        // 项目挖掘题：基于候选人的实际项目经历
        try {
            // 直接从数据库查询简历解析结果
            var latest = resumeAnalysisService.getLatestAnalysisByUser(userId);
            if (latest != null && latest.get("parseResult") != null) {
                Object parseResult = latest.get("parseResult");
                if (parseResult instanceof Map) {
                    Map<?, ?> parseMap = (Map<?, ?>) parseResult;
                    
                    // 提取项目经历
                    Object projects = parseMap.get("projects");
                    if (projects != null && !String.valueOf(projects).trim().isEmpty()) {
                        String projectInfo = limitText(String.valueOf(projects), 1000);
                        promptTemplate = promptTemplate + "\n\n# 项目挖掘题素材（基于候选人实际项目经历）\n" + 
                                       "**重要提醒：请基于候选人的以下实际项目经历，随机抽取 {{PROJECT_COUNT}} 道项目挖掘题。问题应该深入挖掘候选人在这些项目中的技术细节、解决方案和思考过程。**\n\n" + 
                                       "候选人项目经历：\n" + projectInfo + "\n";
                        
                        log.info("成功注入项目信息到面试提示词: userId={}, projectInfo长度={}", userId, projectInfo.length());
                    } else {
                        log.warn("简历解析结果中项目信息为空: userId={}, projects={}", userId, projects);
                        
                        // 尝试从其他字段获取相关信息
                        Object skills = parseMap.get("skills");
                        Object workExperience = parseMap.get("workExperience");
                        Object internships = parseMap.get("internships");
                        
                        StringBuilder alternativeInfo = new StringBuilder();
                        if (skills != null && !String.valueOf(skills).trim().isEmpty()) {
                            alternativeInfo.append("技能特长：").append(skills).append("\n");
                        }
                        if (workExperience != null && !String.valueOf(workExperience).trim().isEmpty()) {
                            alternativeInfo.append("工作经验：").append(workExperience).append("\n");
                        }
                        if (internships != null && !String.valueOf(internships).trim().isEmpty()) {
                            alternativeInfo.append("实习经历：").append(internships).append("\n");
                        }
                        
                        if (alternativeInfo.length() > 0) {
                            String altInfo = limitText(alternativeInfo.toString(), 800);
                            promptTemplate = promptTemplate + "\n\n# 项目挖掘题素材（基于候选人技能和工作经验）\n" + 
                                           "**重要提醒：候选人暂无具体项目经历，请基于以下技能和工作经验，随机抽取 {{PROJECT_COUNT}} 道项目挖掘题。问题应该深入挖掘候选人在这些经历中的技术应用和解决方案。**\n\n" + 
                                           "候选人相关信息：\n" + altInfo + "\n";
                            
                            log.info("使用替代信息生成项目题: userId={}, altInfo长度={}", userId, altInfo.length());
                        } else {
                            log.warn("简历解析结果中所有相关字段都为空，无法生成项目挖掘题: userId={}", userId);
                        }
                    }
                } else {
                    log.warn("简历解析结果格式异常: userId={}, parseResult类型={}", userId, parseResult.getClass().getSimpleName());
                }
            } else {
                log.warn("无法获取简历分析结果: userId={}, latest={}", userId, latest);
            }
        } catch (Exception e) {
            log.error("获取项目信息失败: userId={}, error={}", userId, e.getMessage(), e);
        }

        // 使用前端选择的题量；不再强制只出一道题

        String prompt = promptTemplate
                .replace("{{POSITION}}", position == null ? "" : position)
                .replace("{{RESUME_POINTS}}", resumePoints == null ? "" : resumePoints)
                .replace("{{TARGET_COMPANY}}", targetCompany == null ? "" : targetCompany)
                .replace("{{TOPICS}}", topics == null ? "" : topics)
                .replace("{{CLASSIC_COUNT}}", String.valueOf(classicCount))
                .replace("{{PROJECT_COUNT}}", String.valueOf(projectCount));

        // 添加调试日志，显示题量相关的提示词内容
        log.info("面试提示词题量设置: classicCount={}, projectCount={}", classicCount, projectCount);
        if (prompt.contains("{{CLASSIC_COUNT}}") || prompt.contains("{{PROJECT_COUNT}}")) {
            log.warn("提示词模板中仍有未替换的参数: CLASSIC_COUNT={}, PROJECT_COUNT={}", 
                    prompt.contains("{{CLASSIC_COUNT}}"), prompt.contains("{{PROJECT_COUNT}}"));
        }
        
        // 检查提示词中是否包含题量控制信息
        if (prompt.contains("题量严格控制") || prompt.contains("总共只有")) {
            log.info("提示词包含题量控制信息");
        } else {
            log.warn("提示词缺少题量控制信息");
        }

        // Guardrail 长度控制（<=12000字符），给会话记忆预留空间
        int budget = 11000;
        if (prompt != null && prompt.length() > budget) {
            prompt = limitText(prompt, budget) + "\n\n（为满足输入限制，部分上下文已截断）";
        }

        final Long sid = currentInterviewSessionId;
        final Long uid = userId;

        // 先判断轮次数是否达到上限，若达上限则不再输出任何面试官提示，直接结束SSE
        try {
            List<InterviewMessageDTO> msgList = interviewSessionService.getSessionMessages(sid);
            int currentRoundNow = (msgList == null) ? 0 : msgList.size() / 2;
            int maxRoundsNow = Optional.ofNullable(classicCount).orElse(0) + Optional.ofNullable(projectCount).orElse(0);
            if (currentRoundNow >= maxRoundsNow) {
                log.info("已达题量上限，输出结束语后结束: sessionId={}, currentRound={}, maxRounds={}", sid, currentRoundNow, maxRoundsNow);
                String closing = "好的，本次面试就到这里。感谢你的配合与耐心，我们稍后会给出综合评价与建议。";
                try {
                    interviewSessionService.addAssistantMessage(sid, closing);
                } catch (Exception e) {
                    log.warn("保存结束语失败(忽略): {}", e.getMessage());
                }
                return Flux.just(
                        ServerSentEvent.<String>builder().data(closing).build(),
                        ServerSentEvent.<String>builder().data("[DONE]").build()
                );
            }
        } catch (Exception e) {
            log.warn("轮次校验失败（忽略继续）: {}", e.getMessage());
        }

        // 如果传入了用户回答 message，则直接续聊；否则启动首轮面试
        String contentToSend = (message != null && !message.isBlank()) ? message : prompt;

        // 如果是用户消息，保存到面试会话
        if (message != null && !message.isBlank()) {
            try {
                interviewSessionService.addUserMessage(sid, message);
            } catch (Exception e) {
                log.warn("保存用户消息失败: {}", e.getMessage());
            }
        }

        return aiChatService.interviewStream(uid, sid, contentToSend)
                .map(chunk -> ServerSentEvent.<String>builder().data(chunk).build())
                .concatWith(Flux.just(ServerSentEvent.<String>builder().data("[DONE]").build()));
    }

    /**
     * 回合数检查并在达到上限时触发面试评估，返回结构化JSON并持久化
     */
    @GetMapping("/interview/checkAndEvaluate")
    public Result<Map<String, Object>> checkAndEvaluate(
            @RequestParam("token") String token,
            @RequestParam("sessionId") Long sessionId) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");

            // 读取会话配置与消息
            InterviewSessionDTO session = interviewSessionService.getSessionById(sessionId);
            if (session == null || !Objects.equals(session.getUserId(), userId)) {
                return Result.error("会话不存在或无权限");
            }
            int maxRounds = Optional.ofNullable(session.getClassicCount()).orElse(0)
                    + Optional.ofNullable(session.getProjectCount()).orElse(0);
            List<InterviewMessageDTO> messages = interviewSessionService.getSessionMessages(sessionId);
            int messageCount = (messages == null) ? 0 : messages.size();
            int currentRound = messageCount / 2; // 一问一答计一轮

            Map<String, Object> resp = new HashMap<>();
            resp.put("currentRound", currentRound);
            resp.put("maxRounds", maxRounds);

            if (currentRound < maxRounds) {
                resp.put("needEvaluate", false);
                return Result.success(resp, "未达上限");
            }

            // 达到或超过上限：若已有评估结果则直接返回，避免重复触发
            try {
                InterviewEvaluationDTO existed = interviewSessionService.getEvaluationBySessionId(sessionId);
                if (existed != null && existed.getOverallScore() != null) {
                    Map<String, Object> evalMap = new HashMap<>();
                    evalMap.put("overallScore", existed.getOverallScore());
                    evalMap.put("strengths", parseStringArrayToList(existed.getStrengths()));
                    evalMap.put("weaknesses", parseStringArrayToList(existed.getWeaknesses()));
                    evalMap.put("suggestions", parseStringArrayToList(existed.getSuggestions()));
                    resp.put("needEvaluate", true);
                    resp.put("evaluation", evalMap);
                    return Result.success(resp, "已存在评估结果，直接返回");
                }
            } catch (Exception e) {
                log.warn("读取历史评估失败(将继续生成): sessionId={}, err={}", sessionId, e.getMessage());
            }

            // 达到或超过上限且无历史评估：聚合对话，触发评估
            resp.put("needEvaluate", true);

            StringBuilder dialogue = new StringBuilder();
            if (messages != null) {
                for (InterviewMessageDTO m : messages) {
                    String role = "user".equalsIgnoreCase(m.getRole()) ? "候选人" : "面试官";
                    dialogue.append(role).append(": ").append(m.getContent()).append("\n\n");
                }
            }

            String evalTemplate;
            try {
                evalTemplate = loadResourceText("prompts/interview-evaluation-prompt.txt");
            } catch (Exception e) {
                log.error("读取面试评估提示词失败: {}", e.getMessage());
                return Result.error("面试评估提示词文件缺失");
            }

            String finalPrompt = evalTemplate.replace("{{interview_transcript}}", dialogue.toString());
            ChatResponse chatResponse = myQwenChatModel.chat(UserMessage.from(finalPrompt));
            String evalText = chatResponse.aiMessage().text();
            
            // 如果模型返回的不是JSON格式，尝试重新请求
            if (!evalText.trim().contains("{") || !evalText.trim().contains("}")) {
                log.warn("模型首次返回非JSON格式，尝试重新请求。返回内容: {}", evalText.length() > 200 ? evalText.substring(0, 200) + "..." : evalText);
                
                // 使用更强制性的提示词重新请求
                String forceJsonPrompt = "请严格按照以下JSON格式输出评估结果，不要添加任何其他文字：\n" + 
                    "```json\n" +
                    "{\n" +
                    "  \"overallScore\": \"A\",\n" +
                    "  \"strengths\": [\"优势1\", \"优势2\"],\n" +
                    "  \"weaknesses\": [\"弱点1\", \"弱点2\"],\n" +
                    "  \"suggestions\": [\"建议1\", \"建议2\"]\n" +
                    "}\n" +
                    "```\n\n" +
                    "面试对话内容：\n" + dialogue.toString();
                
                try {
                    ChatResponse retryResponse = myQwenChatModel.chat(UserMessage.from(forceJsonPrompt));
                    String retryText = retryResponse.aiMessage().text();
                    if (retryText.trim().contains("{") && retryText.trim().contains("}")) {
                        evalText = retryText;
                        log.info("重新请求成功，获得JSON格式响应");
                    } else {
                        // 如果重试仍然失败，使用智能分析
                        log.info("重试仍返回非JSON格式，使用智能分析评估");
                        evalText = generateSmartEvaluation(dialogue.toString());
                    }
                } catch (Exception e) {
                    log.warn("重新请求失败: {}", e.getMessage());
                    // 使用智能分析作为备选方案
                    evalText = generateSmartEvaluation(dialogue.toString());
                }
            }

            // 解析JSON（容错：去除markdown围栏，提取大括号段落）
            Map<String, Object> evalMap = parseEvaluationJson(evalText);

            // 持久化到数据库（最小字段）
            String overall = String.valueOf(evalMap.getOrDefault("overallScore", "A"));
            String strengths = String.valueOf(evalMap.getOrDefault("strengths", "[]"));
            String weaknesses = String.valueOf(evalMap.getOrDefault("weaknesses", "[]"));
            String suggestions = String.valueOf(evalMap.getOrDefault("suggestions", "[]"));
            try {
                interviewSessionService.saveEvaluation(sessionId, overall, strengths, weaknesses, suggestions);
            } catch (Exception e) {
                log.warn("评估结果持久化失败: sessionId={}, err={}", sessionId, e.getMessage());
            }

            // 缓存至Redis（可选）
            try {
                String cacheKey = "interview:evaluation:" + sessionId;
                redisTemplate.opsForValue().set(cacheKey, evalMap);
            } catch (Exception e) {
                log.warn("评估结果写入缓存失败: {}", e.getMessage());
            }

            resp.put("evaluation", evalMap);
            return Result.success(resp, "已完成面试评估");

        } catch (Exception e) {
            log.error("检查或评估失败: {}", e.getMessage(), e);
            return Result.error("检查或评估失败");
        }
    }

    // 兼容模型返回包含 ```json 围栏或前后噪声的文本，提取出可解析的 JSON
    private Map<String, Object> parseEvaluationJson(String raw) {
        Map<String, Object> fallback = new HashMap<>();
        fallback.put("overallScore", "A");
        fallback.put("strengths", List.of("模型未返回标准JSON，已回退解析"));
        fallback.put("weaknesses", List.of("数据解析异常"));
        fallback.put("suggestions", List.of("请优化提示词或稍后重试"));

        if (raw == null || raw.isBlank()) {
            log.warn("评估文本为空，使用回退数据");
            return fallback;
        }

        String text = raw.trim();
        log.info("开始解析评估文本，长度: {}", text.length());
        
        // 检查是否包含JSON格式
        if (!text.contains("{") || !text.contains("}")) {
            log.warn("文本不包含JSON格式，尝试从文本中提取评估信息。文本内容: {}", text.length() > 100 ? text.substring(0, 100) + "..." : text);
            return extractEvaluationFromText(raw);
        }
        
        // 去掉 ```json ... ``` 或 ``` ... ``` 围栏
        if (text.startsWith("```")) {
            text = text.replaceAll("(?s)^```json\\s*|(?s)^```\\s*", "");
            text = text.replaceAll("(?s)```$", "");
        }
        
        // 如果仍非以 { 开头，尝试截取第一个 { 到最后一个 }
        int li = text.indexOf('{');
        int ri = text.lastIndexOf('}');
        if (li >= 0 && ri > li) {
            text = text.substring(li, ri + 1);
        }
        
        // 替换 Windows 智能引号等非常见字符
        text = text
                .replace('\u201c', '"')
                .replace('\u201d', '"')
                .replace('\u2018', '\'')
                .replace('\u2019', '\'');

        try {
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> result = mapper.readValue(text, new TypeReference<Map<String, Object>>() {});
            
            // 验证必要字段是否存在
            if (!result.containsKey("overallScore") || !result.containsKey("strengths") || 
                !result.containsKey("weaknesses") || !result.containsKey("suggestions")) {
                log.warn("评估JSON缺少必要字段，回退: {}", result.keySet());
                return fallback;
            }
            
            // 验证和清理数据
            result = validateAndCleanEvaluationData(result);
            
            log.info("评估JSON解析成功: overallScore={}, strengths={}, weaknesses={}, suggestions={}", 
                    result.get("overallScore"), result.get("strengths"), result.get("weaknesses"), result.get("suggestions"));
            return result;
        } catch (Exception e) {
            log.warn("评估JSON解析失败，原始文本: {}, 错误: {}", text, e.getMessage());
            return fallback;
        }
    }

    // 智能生成评估结果
    private String generateSmartEvaluation(String dialogue) {
        try {
            // 分析对话内容
            String[] lines = dialogue.split("\n");
            List<String> userAnswers = new ArrayList<>();
            
            // 提取用户回答
            for (String line : lines) {
                if (line.startsWith("候选人:") || line.startsWith("user:")) {
                    userAnswers.add(line.substring(line.indexOf(":") + 1).trim());
                }
            }
            
            // 分析回答质量
            int totalAnswers = userAnswers.size();
            int detailedAnswers = 0;
            int correctAnswers = 0;
            int shortAnswers = 0;
            
            for (String answer : userAnswers) {
                if (answer.length() > 100) {
                    detailedAnswers++;
                } else if (answer.length() < 30) {
                    shortAnswers++;
                }
                
                // 简单的正确性判断（基于关键词）
                String lowerAnswer = answer.toLowerCase();
                if (lowerAnswer.contains("正确") || lowerAnswer.contains("是的") || 
                    lowerAnswer.contains("可以") || lowerAnswer.contains("应该")) {
                    correctAnswers++;
                }
            }
            
            // 计算评估等级
            String overallScore = "A";
            List<String> strengths = new ArrayList<>();
            List<String> weaknesses = new ArrayList<>();
            List<String> suggestions = new ArrayList<>();
            
            if (totalAnswers > 0) {
                double detailRatio = (double) detailedAnswers / totalAnswers;
                double correctRatio = (double) correctAnswers / totalAnswers;
                double shortRatio = (double) shortAnswers / totalAnswers;
                
                if (detailRatio > 0.7 && correctRatio > 0.8) {
                    overallScore = "S";
                    strengths.add("回答详细深入，逻辑清晰");
                    strengths.add("展现专家级理解能力");
                } else if (detailRatio > 0.5 && correctRatio > 0.6) {
                    overallScore = "A+";
                    strengths.add("回答基本正确，逻辑较好");
                    strengths.add("展现良好理解能力");
                } else if (correctRatio > 0.4) {
                    overallScore = "A";
                    strengths.add("回答基本正确");
                    if (shortRatio > 0.5) {
                        weaknesses.add("回答过于简略");
                        suggestions.add("建议提供更详细的解释");
                    }
                } else if (shortRatio > 0.6) {
                    overallScore = "A-";
                    weaknesses.add("回答过于简略");
                    weaknesses.add("缺乏详细解释");
                    suggestions.add("建议提供更详细的回答");
                } else {
                    overallScore = "B";
                    weaknesses.add("回答质量不佳");
                    suggestions.add("建议加强基础知识学习");
                }
            }
            
            // 设置默认值
            if (strengths.isEmpty()) {
                strengths.add("基于对话分析，候选人表现一般");
            }
            if (weaknesses.isEmpty()) {
                weaknesses.add("需要更多详细信息进行准确评估");
            }
            if (suggestions.isEmpty()) {
                suggestions.add("建议提供更详细的技能和岗位要求信息");
            }
            
            // 生成JSON格式的评估结果
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> evaluation = new HashMap<>();
            evaluation.put("overallScore", overallScore);
            evaluation.put("strengths", strengths);
            evaluation.put("weaknesses", weaknesses);
            evaluation.put("suggestions", suggestions);
            
            String jsonResult = mapper.writeValueAsString(evaluation);
            log.info("智能生成评估结果: overallScore={}, 总回答数={}, 详细回答数={}, 简短回答数={}", 
                    overallScore, totalAnswers, detailedAnswers, shortAnswers);
            
            return jsonResult;
            
        } catch (Exception e) {
            log.error("智能评估生成失败: {}", e.getMessage());
            // 返回默认评估结果
            return "{\"overallScore\":\"A\",\"strengths\":[\"基于对话分析，候选人表现一般\"],\"weaknesses\":[\"需要更多详细信息进行准确评估\"],\"suggestions\":[\"建议提供更详细的技能和岗位要求信息\"]}";
        }
    }

    // 从非JSON文本中提取评估信息
    private Map<String, Object> extractEvaluationFromText(String text) {
        Map<String, Object> result = new HashMap<>();
        
        // 分析文本内容，判断回答质量
        String lowerText = text.toLowerCase();
        
        // 分析回答质量指标
        boolean hasDetailedExplanation = lowerText.contains("详细") || lowerText.contains("具体") || 
                                       lowerText.contains("深入") || lowerText.contains("全面");
        boolean hasCorrectConcepts = lowerText.contains("正确") || lowerText.contains("准确") || 
                                   lowerText.contains("符合") || lowerText.contains("标准");
        boolean hasLogicalStructure = lowerText.contains("逻辑") || lowerText.contains("清晰") || 
                                    lowerText.contains("条理") || lowerText.contains("结构");
        boolean hasDeepUnderstanding = lowerText.contains("理解") || lowerText.contains("掌握") || 
                                     lowerText.contains("精通") || lowerText.contains("深入");
        
        // 分析负面指标
        boolean hasErrors = lowerText.contains("错误") || lowerText.contains("不正确") || 
                          lowerText.contains("问题") || lowerText.contains("不足");
        boolean isTooSimple = lowerText.contains("简单") || lowerText.contains("基础") || 
                            lowerText.contains("浅显") || lowerText.contains("不够详细");
        boolean lacksUnderstanding = lowerText.contains("不理解") || lowerText.contains("不清楚") || 
                                   lowerText.contains("缺乏") || lowerText.contains("不足");
        
        // 根据分析结果确定评估等级
        String overallScore = "A";
        List<String> strengths = new ArrayList<>();
        List<String> weaknesses = new ArrayList<>();
        List<String> suggestions = new ArrayList<>();
        
        if (hasDetailedExplanation && hasCorrectConcepts && hasLogicalStructure && hasDeepUnderstanding) {
            overallScore = "S";
            strengths.add("回答详细深入，逻辑清晰");
            strengths.add("展现专家级理解能力");
        } else if (hasCorrectConcepts && (hasDetailedExplanation || hasLogicalStructure)) {
            overallScore = "A+";
            strengths.add("回答基本正确，逻辑较好");
            strengths.add("展现良好理解能力");
        } else if (hasCorrectConcepts && !hasErrors) {
            overallScore = "A";
            strengths.add("回答基本正确");
            if (isTooSimple) {
                weaknesses.add("回答过于简略");
                suggestions.add("建议提供更详细的解释");
            }
        } else if (hasErrors || isTooSimple) {
            overallScore = "A-";
            weaknesses.add("回答存在明显不足");
            if (hasErrors) {
                weaknesses.add("技术概念理解有误");
                suggestions.add("建议加强基础知识学习");
            }
            if (isTooSimple) {
                suggestions.add("建议提供更详细的回答");
            }
        } else if (lacksUnderstanding) {
            overallScore = "B";
            weaknesses.add("缺乏基本理解");
            suggestions.add("建议加强基础概念学习");
        }
        
        // 设置默认值
        if (strengths.isEmpty()) {
            strengths.add("基于文本分析，候选人表现一般");
        }
        if (weaknesses.isEmpty()) {
            weaknesses.add("需要更多详细信息进行准确评估");
        }
        if (suggestions.isEmpty()) {
            suggestions.add("建议提供更详细的技能和岗位要求信息");
        }
        
        result.put("overallScore", overallScore);
        result.put("strengths", strengths);
        result.put("weaknesses", weaknesses);
        result.put("suggestions", suggestions);
        
        log.info("从文本中提取评估结果: overallScore={}, strengths={}, weaknesses={}", 
                overallScore, strengths, weaknesses);
        return result;
    }

    // 验证和清理评估数据
    private Map<String, Object> validateAndCleanEvaluationData(Map<String, Object> data) {
        Map<String, Object> cleaned = new HashMap<>();
        
        // 验证overallScore
        String overallScore = String.valueOf(data.get("overallScore"));
        if (!overallScore.matches("^[SA][+-]?$|^B$")) {
            log.warn("无效的overallScore: {}, 使用默认值A", overallScore);
            overallScore = "A";
        }
        cleaned.put("overallScore", overallScore);
        
        // 验证和清理strengths
        Object strengthsObj = data.get("strengths");
        List<String> strengths = parseStringArrayToList(String.valueOf(strengthsObj));
        if (strengths.isEmpty()) {
            strengths = List.of("表现良好");
        }
        cleaned.put("strengths", strengths);
        
        // 验证和清理weaknesses
        Object weaknessesObj = data.get("weaknesses");
        List<String> weaknesses = parseStringArrayToList(String.valueOf(weaknessesObj));
        if (weaknesses.isEmpty()) {
            weaknesses = List.of("无明显弱点");
        }
        cleaned.put("weaknesses", weaknesses);
        
        // 验证和清理suggestions
        Object suggestionsObj = data.get("suggestions");
        List<String> suggestions = parseStringArrayToList(String.valueOf(suggestionsObj));
        if (suggestions.isEmpty()) {
            suggestions = List.of("继续保持当前水平");
        }
        cleaned.put("suggestions", suggestions);
        
        return cleaned;
    }

    // 将存储为字符串的数组字段（可能是形如 ["a","b"] 的JSON，也可能是逗号分隔文本）转为List
    private List<String> parseStringArrayToList(String src) {
        try {
            if (src == null || src.isBlank()) return Collections.emptyList();
            String text = src.trim();
            // 优先当 JSON 数组解析（严格）
            if (text.startsWith("[") && text.endsWith("]")) {
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    return mapper.readValue(text, new TypeReference<List<String>>() {});
                } catch (Exception ignore) {
                    // 兼容无引号的方括号数组：[条目1, 条目2]
                    String inner = text.substring(1, text.length() - 1).trim();
                    if (inner.isEmpty()) return Collections.emptyList();
                    String[] rough = inner.split("[\n,，、；;]+");
                    List<String> out = new ArrayList<>();
                    for (String p : rough) {
                        String s = p.trim();
                        if (!s.isEmpty()) out.add(s);
                    }
                    return out;
                }
            }
            // 退化为按换行或逗号切分
            String[] parts = text.split("[\n,，、；;]+");
            List<String> out = new ArrayList<>();
            for (String p : parts) {
                String s = p.trim();
                if (!s.isEmpty()) out.add(s);
            }
            return out;
        } catch (Exception e) {
            log.warn("解析字符串数组失败，回退为空列表: {}", e.getMessage());
            return Collections.emptyList();
        }
    }

    /**
     * 读取classpath下文本资源
     */
    private String loadResourceText(String path) throws Exception {
        try (var in = Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream(path))) {
            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
        }
    }

    /**
     * 根据 topics 过滤知识库内容：按二级标题筛选相关段落
     */
    private String filterKnowledgeByTopics(String markdown, String topics) {
        if (markdown == null || markdown.isBlank()) return null;
        if (topics == null || topics.isBlank()) return null;
        String t = topics.replace('、', ',');
        Set<String> keys = new HashSet<>();
        for (String k : t.split(",")) {
            String s = k.trim(); if (!s.isEmpty()) keys.add(s.toLowerCase());
        }
        // 简单切分：按“## ”分节，匹配节名包含关键词
        StringBuilder sb = new StringBuilder();
        String[] sections = markdown.split("\n## ");
        for (String sec : sections) {
            String head = sec.split("\n",2)[0].toLowerCase();
            for (String k : keys) {
                if (head.contains(k.toLowerCase())) {
                    sb.append("## ").append(sec.trim()).append("\n\n");
                    break;
                }
            }
        }
        String out = sb.toString();
        if (out.length() > 2200) {
            return out.substring(0, 2200) + "\n...（知识库片段已截断）\n";
        }
        return out;
    }

    /** 限制字符串长度（按字符数粗略控制） */
    private String limitText(String s, int max) {
        if (s == null) return null;
        if (s.length() <= max) return s;
        return s.substring(0, max);
    }

    /**
     * 查询数据库中的历史对话
     */
    @GetMapping("/history")
    public Result<List<Object>> history(@RequestParam(value = "limit", required = false) Integer limit,
                                              @RequestParam("token") String token) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            List<Object> list = aiChatService.listHistory(userId, limit);
            return Result.success(list, "查询成功");
        } catch (Exception e) {
            log.error("查询历史对话失败: {}", e.getMessage());
            return Result.error("查询失败");
        }
    }

    /**
     * 面试历史（来自 interview 表），供前端左栏展示真实数据
     */
    @GetMapping("/interview/history")
    public Result<List<java.util.Map<String, Object>>> interviewHistoryDb(@RequestParam("token") String token) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");
            List<java.util.Map<String, Object>> list = interviewMapper.listByUser(userId);
            return Result.success(list);
        } catch (Exception e) {
            log.error("查询面试历史失败: {}", e.getMessage());
            return Result.error("查询失败");
        }
    }

    /**
     * 获取面试对话的会话列表（仅面试相关，与普通问答分离）
     */
    @GetMapping("/interview/sessions")
    public Result<List<InterviewSessionDTO>> getInterviewSessions(@RequestParam("token") String token) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");
            
            // 使用新的面试会话服务
            List<InterviewSessionDTO> sessions = interviewSessionService.getUserSessions(userId);
            return Result.success(sessions, "获取面试会话列表成功");
        } catch (Exception e) {
            log.error("获取面试会话列表失败: {}", e.getMessage(), e);
            return Result.error("获取面试会话列表失败");
        }
    }

    /**
     * 创建面试专用会话
     */
    @PostMapping("/interview/createSession")
    public Result<InterviewSessionDTO> createInterviewSession(
            @RequestParam("token") String token,
            @RequestParam("interviewerType") String interviewerType,
            @RequestParam(value = "topics", required = false) String topics,
            @RequestParam(value = "classicCount", required = false, defaultValue = "5") Integer classicCount,
            @RequestParam(value = "projectCount", required = false, defaultValue = "2") Integer projectCount) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");
            
            // 创建面试专用会话
            String interviewerTypeEn = getInterviewerTypeEn(interviewerType);
            String sessionTitle = "Interview-" + interviewerTypeEn + "-" + System.currentTimeMillis();
            InterviewSessionDTO session = interviewSessionService.createSession(
                userId, null, sessionTitle, interviewerType, topics, classicCount, projectCount);
            return Result.success(session, "创建面试会话成功");
        } catch (Exception e) {
            log.error("创建面试会话失败: {}", e.getMessage(), e);
            return Result.error("创建面试会话失败");
        }
    }

    /**
     * 获取面试会话消息
     */
    @GetMapping("/interview/messages")
    public Result<List<InterviewMessageDTO>> getInterviewMessages(
            @RequestParam("token") String token,
            @RequestParam("sessionId") Long sessionId) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");
            
            // 验证会话所有权
            InterviewSessionDTO session = interviewSessionService.getSessionById(sessionId);
            if (session == null || !session.getUserId().equals(userId)) {
                return Result.error("会话不存在或无权限访问");
            }
            
            List<InterviewMessageDTO> messages = interviewSessionService.getSessionMessages(sessionId);
            return Result.success(messages, "获取面试消息成功");
        } catch (Exception e) {
            log.error("获取面试消息失败: {}", e.getMessage(), e);
            return Result.error("获取面试消息失败");
        }
    }

    /**
     * 删除面试会话
     */
    @DeleteMapping("/interview/deleteSession")
    public Result<String> deleteInterviewSession(
            @RequestParam("token") String token,
            @RequestParam("sessionId") Long sessionId) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");
            
            interviewSessionService.deleteSession(sessionId, userId);
            return Result.success("删除面试会话成功");
        } catch (Exception e) {
            log.error("删除面试会话失败: {}", e.getMessage(), e);
            return Result.error("删除面试会话失败");
        }
    }

    /**
     * 新建面试历史记录（直接创建interview_session）
     */
    @PostMapping("/interview/create")
    public Result<Map<String, Object>> createInterview(
            @RequestParam("token") String token,
            @RequestParam(value = "interviewerType", required = false, defaultValue = "4") Integer interviewerType,
            @RequestParam(value = "interviewerTypeDesc", required = false, defaultValue = "普通面") String interviewerTypeDesc,
            @RequestParam(value = "topics", required = false, defaultValue = "") String topics,
            @RequestParam(value = "classicCount", required = false, defaultValue = "5") Integer classicCount,
            @RequestParam(value = "projectCount", required = false, defaultValue = "2") Integer projectCount
    ) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");

            // 直接创建interview_session，跳过interview表
            String interviewerTypeEn = getInterviewerTypeEn(interviewerType);
            String sessionTitle = "Interview-" + interviewerTypeEn + "-" + System.currentTimeMillis();
            InterviewSessionDTO session = interviewSessionService.createSession(
                userId, null, sessionTitle, String.valueOf(interviewerType), topics, classicCount, projectCount);
            
            Map<String, Object> result = new HashMap<>();
            result.put("interviewId", session.getId());
            result.put("sessionTitle", session.getSessionTitle());
            result.put("classicCount", classicCount);
            result.put("projectCount", projectCount);
            
            return Result.success(result, "创建面试会话成功");
        } catch (Exception e) {
            log.error("创建面试会话失败: {}", e.getMessage(), e);
            return Result.error("创建面试会话失败");
        }
    }

    /**
     * 删除面试历史记录
     */
    @DeleteMapping("/interview/delete")
    public Result<String> deleteInterview(
            @RequestParam("token") String token,
            @RequestParam("id") Long id
    ) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) return Result.error("用户未登录");

            int n = interviewMapper.deleteByIdAndUser(id, userId);
            if (n > 0) return Result.success("删除成功");
            return Result.error("删除失败或无权限");
        } catch (Exception e) {
            log.error("删除面试记录失败: {}", e.getMessage());
            return Result.error("删除失败");
        }
    }

    /**
     * 获取AI聊天历史记录（包含问题和回答）
     * @param token JWT Token
     * @return 聊天历史记录
     */
    @GetMapping("/getChatHistory")
    public Result<List<Object>> getChatHistory(@RequestParam("token") String token) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            
            List<Object> historyList = aiChatService.getChatHistory(userId);
            return Result.success(historyList, "获取聊天历史记录成功");
        } catch (Exception e) {
            log.error("获取AI聊天历史记录失败: {}", e.getMessage(), e);
            return Result.error("获取聊天历史记录失败");
        }
    }
    
    /**
     * 获取用户的聊天会话列表
     * @param token JWT Token
     * @return 会话列表
     */
    @GetMapping("/getChatSessions")
    public Result<List<ChatSessionDTO>> getChatSessions(@RequestParam("token") String token) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            
            List<ChatSessionDTO> sessions = chatMemoryService.getUserSessions(userId);
            return Result.success(sessions, "获取会话列表成功");
        } catch (Exception e) {
            log.error("获取聊天会话列表失败: {}", e.getMessage(), e);
            return Result.error("获取会话列表失败");
        }
    }
    
    /**
     * 获取会话的所有消息
     * @param token JWT Token
     * @param sessionId 会话ID
     * @return 消息列表
     */
    @GetMapping("/getSessionMessages")
    public Result<List<ChatMessageDTO>> getSessionMessages(
            @RequestParam("token") String token,
            @RequestParam("sessionId") Long sessionId) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            
            List<ChatMessageDTO> messages = chatMemoryService.getSessionMessages(sessionId);
            return Result.success(messages, "获取会话消息成功");
        } catch (Exception e) {
            log.error("获取会话消息失败: {}", e.getMessage(), e);
            return Result.error("获取会话消息失败");
        }
    }
    
    /**
     * 创建新的聊天会话
     * @param token JWT Token
     * @param initialMessage 初始消息
     * @return 会话信息
     */
    @PostMapping("/createChatSession")
    public Result<ChatSessionDTO> createChatSession(
            @RequestParam("token") String token,
            @RequestParam("initialMessage") String initialMessage) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            
            ChatSessionDTO session = chatMemoryService.createChatSession(userId, initialMessage);
            return Result.success(session, "创建会话成功");
        } catch (Exception e) {
            log.error("创建聊天会话失败: {}", e.getMessage(), e);
            return Result.error("创建会话失败");
        }
    }
    
    /**
     * 删除聊天会话
     * @param token JWT Token
     * @param sessionId 会话ID
     * @return 操作结果
     */
    @DeleteMapping("/deleteChatSession")
    public Result<String> deleteChatSession(
            @RequestParam("token") String token,
            @RequestParam("sessionId") Long sessionId) {
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            Long userId = Long.valueOf(claims.get("userId").toString());
            if (userId == null) {
                return Result.error("用户未登录");
            }
            
            chatMemoryService.deleteSession(sessionId, userId);
            return Result.success("删除会话成功");
        } catch (Exception e) {
            log.error("删除聊天会话失败: {}", e.getMessage(), e);
            return Result.error("删除会话失败");
        }
    }

    /**
     * 处理OPTIONS预检请求
     */
    @RequestMapping(value = "/saveAiTalks", method = RequestMethod.OPTIONS)
    public ResponseEntity<Void> handleSaveAiTalksOptions() {
        return ResponseEntity.ok().build();
    }

    /**
     * 保存AI对话历史
     */
    @PostMapping("/saveAiTalks")
    public Result<String> saveAiTalks(@RequestBody List<Object> aiTalkList) {
        try {
            Long userId = BaseContext.getCurrentId();
            if (userId == null) {
                return Result.error("用户未登录");
            }

            aiChatService.saveAiTalks(userId, aiTalkList);
            return Result.success("保存成功");
        } catch (Exception e) {
            log.error("保存AI对话历史失败: {}", e.getMessage(), e);
            return Result.error("保存失败");
        }
    }

    /**
     * 处理OPTIONS预检请求
     */
    @RequestMapping(value = "/clearAiTalks", method = RequestMethod.OPTIONS)
    public ResponseEntity<Void> handleClearAiTalksOptions() {
        return ResponseEntity.ok().build();
    }

    /**
     * 清除AI对话历史
     */
    @DeleteMapping("/clearAiTalks")
    public Result<String> clearAiTalks() {
        try {
            Long userId = BaseContext.getCurrentId();
            if (userId == null) {
                return Result.error("用户未登录");
            }

            aiChatService.clearAiTalks(userId);
            return Result.success("清除成功");
        } catch (Exception e) {
            log.error("清除AI对话历史失败: {}", e.getMessage(), e);
            return Result.error("清除失败");
        }
    }

    /**
     * 根据面试官类型获取英文描述
     * @param interviewerType 面试官类型（字符串或数字）
     * @return 英文描述
     */
    private String getInterviewerTypeEn(String interviewerType) {
        return switch (interviewerType) {
            case "pressure", "1" -> "Pressure";
            case "gentle", "2" -> "Gentle";
            case "kpi", "3" -> "KPI";
            case "normal", "4" -> "Normal";
            default -> "Normal";
        };
    }

    /**
     * 根据面试官类型获取英文描述（数字类型）
     * @param interviewerType 面试官类型（数字）
     * @return 英文描述
     */
    private String getInterviewerTypeEn(Integer interviewerType) {
        return switch (interviewerType) {
            case 1 -> "Pressure";
            case 2 -> "Gentle";
            case 3 -> "KPI";
            case 4 -> "Normal";
            default -> "Normal";
        };
    }
}
